package com.lanzuo.collector.updater.service;

import cn.hutool.core.io.FileUtil;
import com.lanzuo.collector.updater.config.SpringContextHolder;
import com.lanzuo.collector.updater.http.NginxFileInterface;
import com.lanzuo.collector.updater.utils.WinServiceUtil;
import lombok.extern.slf4j.Slf4j;
import net.schmizz.sshj.sftp.RemoteResourceInfo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 *
 */
@Slf4j
@Service
public class FileUpdateService {
    private final static String DEFAULT_PROJECT_DIR = "D:\\BlueScada\\collector\\";

    @Resource
    RemoteFileLister remoteFileLister;

    @Resource
    NginxFileInterface nginxFileInterface;

    ExecutorService executorService = Executors.newSingleThreadExecutor();

    private String formatBytes(long bytes) {
        if (bytes < 1024) return bytes + " B";
        int exp = (int) (Math.log(bytes) / Math.log(1024));
        String unit = "KMGTPE".charAt(exp - 1) + "B";
        return String.format("%.1f %s", bytes / Math.pow(1024, exp), unit);
    }

    private String repeat(String str, int count) {
        if (count <= 0) return "";
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) sb.append(str);
        return sb.toString();
    }

    public void start() {
        executorService.execute(() -> {
            while (true) {
                try {
                    // 每隔10s检查一次
                    TimeUnit.SECONDS.sleep(10);

                    RemoteResourceInfo remoteResourceInfo = remoteFileLister.getLatestFile().orElse(null);
                    if (remoteResourceInfo == null) continue;

                    String fileName = remoteResourceInfo.getName();
                    log.info("Got latest file,name: {}", fileName);

                    if (!checkVersionChanged(fileName)) {
                        log.info(" 文件没有改变，不更新包。");
                        if (!WinServiceUtil.isServiceRunning()) {
                            WinServiceUtil.commandWinService("start");
                        }
                        continue;
                    }

                    log.info(" 文件版本改变，即将更新包...");

                    AtomicReference<String> lastLog = new AtomicReference<>("");
                    AtomicInteger logCount = new AtomicInteger(0);
                    nginxFileInterface.downloadFile(fileName, progress -> {
                        logCount.getAndIncrement();
                        if (progress.isBegin()) {
                            log.info("开始下载文件: {}, 总大小: {} 字节", fileName, progress.getTotalBytes());
                        }

                        if (progress.isDone()) {
                            log.info("--------   下载完成！准备重启服务...   --------");
                            updateService(fileName);
                            return;
                        }

                        // 计算百分比（0 ~ 100）
                        int percent = (int) Math.round(progress.getRate() * 100);

                        // 构建进度条：20个字符宽度
                        int barWidth = 20;
                        int filled = (int) ((double) percent / 100 * barWidth);
                        String progressBar = repeat("█", filled) + repeat("░", barWidth - filled);
                        String currentLog = String.format("[%s] %d%% (%s / %s)",
                                progressBar,
                                percent,
                                formatBytes(progress.getCurrentBytes()),
                                formatBytes(progress.getTotalBytes())
                        );

                        // 只有当进度变化时才打印（避免刷屏）
                        if (!currentLog.equals(lastLog.get()) && logCount.get() % 120 == 0) {
                            log.info("下载进度: {}", currentLog);
                            lastLog.set(currentLog);
                        }
                    });
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    public boolean checkVersionChanged(String newFileName) {
        String version = newFileName.split("\\.")[0].split("@")[1];
        String targetDir = SpringContextHolder.getProperty("forest.variables.target_dir", DEFAULT_PROJECT_DIR);
        String versionFileName = targetDir + "version.txt";
        File versionFile = new File(versionFileName);
        if (!FileUtil.exist(versionFile)) {
            // 创建文件
            versionFile = FileUtil.touch(versionFile);
        }

        String originVersion = FileUtil.readString(versionFile, Charset.defaultCharset());

        log.info("new version:{}, old version:{}", version, originVersion);
        return !originVersion.equals(version);
    }

    /**
     * 更新服务
     */
    public void updateService(String newVersionFileName) {
        String targetFileName = SpringContextHolder.getProperty("target.file_name");
        String targetDir = SpringContextHolder.getProperty("forest.variables.target_dir", DEFAULT_PROJECT_DIR);
        String filePath = targetDir + targetFileName;
        String newFilePath = targetDir + newVersionFileName;

        // 记录版本
        String versionFileName = targetDir + "version.txt";
        File versionFile = new File(versionFileName);

        String version = newVersionFileName.split("\\.")[0].split("@")[1];

        WinServiceUtil.commandWinService("stop");
        // 删除原文件
        FileUtil.del(new File(filePath));

        // 重命名最新文件为源文件名称
        FileUtil.rename(new File(newFilePath), filePath, true);

        try {
            // 等到服务完全停止后，再启动
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        // 启动服务
        WinServiceUtil.commandWinService("start");

        // 记录版本
        FileUtil.writeString(version, versionFile, Charset.defaultCharset());
    }

}

